package com.javatip.project.deep_learning.trainMission.service;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

import com.javatip.common.utils.RunPythonScript;
import com.javatip.common.utils.file.FileUtils;
import com.javatip.project.deep_learning.app01Dataset.domain.App01Dataset;
import com.javatip.project.deep_learning.app01Dataset.service.IApp01DatasetService;
import com.javatip.project.deep_learning.model.domain.Model;
import com.javatip.project.deep_learning.model.service.ModelServiceImpl;
import com.javatip.project.deep_learning.predict.domain.Predict;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.javatip.project.deep_learning.trainMission.mapper.TrainMissionMapper;
import com.javatip.project.deep_learning.trainMission.domain.TrainMission;
import com.javatip.common.utils.text.Convert;
import com.javatip.common.utils.Utils;

/**
 * 训练任务 服务层实现
 *
 * @author 袁伟
 * @date 2024-07-12
 */
@Service
public class TrainMissionServiceImpl implements ITrainMissionService {
    @Autowired
    private TrainMissionMapper trainMissionMapper;
    @Autowired
    private ModelServiceImpl modelServiceImpl;
    @Autowired
    private IApp01DatasetService app01DatasetService;


    /**
     * 查询训练任务信息
     *
     * @param id 训练任务ID
     * @return 训练任务信息
     */
    @Override
    public TrainMission selectTrainMissionById(Integer id) {
        return trainMissionMapper.selectTrainMissionById(id);
    }

    /**
     * 查询训练任务列表
     *
     * @param trainMission 训练任务信息
     * @return 训练任务集合
     */
    @Override
    public List<TrainMission> selectTrainMissionList(TrainMission trainMission) {
        return trainMissionMapper.selectTrainMissionList(trainMission);
    }

    /**
     * 新增训练任务
     *
     * @param trainMission 训练任务信息
     * @return 结果
     */
    @Override
    public int insertTrainMission(TrainMission trainMission) {
//        System.out.println("trainMission: " + trainMission);
        return trainMissionMapper.insertTrainMission(trainMission);
    }

    /**
     * 修改训练任务
     *
     * @param trainMission 训练任务信息
     * @return 结果
     */
    @Override
    public int updateTrainMission(TrainMission trainMission) {
        return trainMissionMapper.updateTrainMission(trainMission);
    }

    /**
     * 删除训练任务对象
     *
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteTrainMissionByIds(String ids) {
        return trainMissionMapper.deleteTrainMissionByIds(Convert.toStrArray(ids));
    }


    // 保存每个训练任务的进程信息
    private final ConcurrentHashMap<Integer, Process> processMap = new ConcurrentHashMap<>();
    private final ExecutorService executorService = Executors.newCachedThreadPool();
    // 全局标志，表示是否正在停止任务
    private volatile boolean stopFlag = false;
    // 全局锁，确保任务的同步执行
    private final ReentrantLock lock = new ReentrantLock();

    @Override
    // 启动单独训练
    public int startSingleTraining(int id) {
        if (stopFlag) {
            System.out.println("全局停止标志已设置，不启动新的训练任务");
            return 1; // 表示未执行新的任务
        }

        TrainMission trainMission = trainMissionMapper.selectTrainMissionById(id);
        if (trainMission == null) {
            System.out.println("训练任务未找到");
            return 1; // 数据库查询失败
        }

        int batchSize = trainMission.getBatchSize();
        int epoch = trainMission.getMaxEpoch();
        int earlyStop = trainMission.getEarlyStop();
        double lr = trainMission.getOpLr();
//        System.out.println("id：" + id);

        // 更新训练状态为“训练中”
        trainMission.setStatus("训练中");
        trainMission.setRunning(true); // 设置为运行中
        trainMission.setBeginTime(new java.util.Date());
        // 设置结束时间
        trainMission.setEndTime(null);
        trainMissionMapper.updateTrainMission(trainMission);

        //获取当前路径
        String currentPath = System.getProperty("user.dir").replace("\\","/");
        String parentParentPath = Utils.getParentPath(currentPath, 0);
//		parentParentPath: /home/jolly/develop/project/java
        currentPath = parentParentPath + "/src/main/resources/CorsicanFire/segmentation";
//        System.out.println("currentPath: " + currentPath);

        // 启动 Python 脚本
//		trainMissionId, modelName, model_path, datasetTrain, datasetTrainName, datasetVal, datasetValName, batchSize,epoch, earlyStop, lr
        //打印所有参数
//        System.out.println("trainMissionId: " + id);
//        System.out.println("modelName: " + trainMission.getModel());
//        System.out.println("model_path: " + modelServiceImpl.selectModelById(trainMission.getModelId()).getLocation());
//        System.out.println("datasetTrain: " + app01DatasetService.selectApp01DatasetById(trainMission.getDatasetTrainId()).getLocation());
//        System.out.println("datasetTrainName: " + app01DatasetService.selectApp01DatasetById(trainMission.getDatasetTrainId()).getName());
//        System.out.println("datasetVal: " + app01DatasetService.selectApp01DatasetById(trainMission.getDatasetValId()).getLocation());
//        System.out.println("datasetValName: " + app01DatasetService.selectApp01DatasetById(trainMission.getDatasetValId()).getName());
//        System.out.println("batchSize: " + batchSize);
//        System.out.println("minEpoch: " + trainMission.getMinEpoch());
//        System.out.println("epoch: " + epoch);
//        System.out.println("earlyStop: " + earlyStop);
//        System.out.println("lr: " + lr);

//        System.out.println("trainMission.getIsWeight(): " + trainMission.getIsWeight());

        if (trainMission.getIsWeight()) {
            // 构建源文件路径
//            System.out.println("加载预训练模型");
            String pretrainModelLocation = modelServiceImpl.selectModelById(trainMission.getModelId()).getLocation();
            int lastSlashIndex = pretrainModelLocation.lastIndexOf("/");
            if (lastSlashIndex != -1) {
                pretrainModelLocation = pretrainModelLocation.substring(0, lastSlashIndex);
            }

            // 拼接最终的源文件路径
            String sourceFilePath = pretrainModelLocation + "/1.pth";

            // 构建目标文件路径
            String pretrainModelPath = parentParentPath + "/src/main/resources/trainResult" + "/" + trainMission.getId() + "/predictResult/1.pth";

            // 调用文件复制方法
            try {
                Utils.copyFile(sourceFilePath, pretrainModelPath);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        // 训练异常记录txt文件存储位置
        String exceptionRecordPath = parentParentPath + "/src/main/resources/trainResult" + "/" + trainMission.getId() + "/exceptionRecord.txt";
        // 确保目录存在
        File exceptionFile = new File(exceptionRecordPath);
        exceptionFile.getParentFile().mkdirs();
        Model model = modelServiceImpl.selectModelById(trainMission.getModelId());
        Process process = RunPythonScript.runCommandWithParaProcess(
                currentPath + "/RunCommand.py",
                id,
                trainMission.getModel(),
                model.getUserId(),
                app01DatasetService.selectApp01DatasetById(trainMission.getDatasetTrainId()).getLocation(),
                app01DatasetService.selectApp01DatasetById(trainMission.getDatasetTrainId()).getName(),
                app01DatasetService.selectApp01DatasetById(trainMission.getDatasetValId()).getLocation(),
                app01DatasetService.selectApp01DatasetById(trainMission.getDatasetValId()).getName(),
                batchSize,
                trainMission.getMinEpoch(),
                epoch,
                earlyStop,
                lr,
                trainMission.getModelId(),
                app01DatasetService.selectApp01DatasetById(trainMission.getDatasetTrainId()).getHeight(),
                model.getInputChannel(),
                model.getOutputChannel(),
                exceptionRecordPath);
        if (process != null) {
            System.out.println("process正常");
            processMap.put(id, process);
            System.out.println("processMap: " + processMap.toString());

            executorService.submit(() -> {
                try {
                    int result = process.waitFor();
//                    System.out.println("result:"+result);
                    if (result == 0) {
                        trainMission.setStatus("已完成"); // 训练成功完成
                        trainMission.setEndTime(new java.util.Date());
                        // 训练完后删除除了predictResult文件夹以外的所有文件
                        File parentDir = new File(parentParentPath + "/src/main/resources/trainResult/" + trainMission.getId());

                        // 如果文件夹不存在，直接返回
                        if (!parentDir.exists() || !parentDir.isDirectory()) {
                            return;
                        }

                        // 获取文件夹中的所有文件和文件夹
                        File[] files = parentDir.listFiles();

                        if (files != null) {
                            for (File file : files) {
                                // 检查是否是predictResult文件夹，排除它
                                if (file.isDirectory() && !file.getName().equals("predictResult")) {
                                    // 调用你的deleteFolderFile方法删除文件夹及其内容
                                    FileUtils.deleteFolderFile(file.getAbsolutePath()); // 删除文件夹及其内容
                                } else if (file.isFile()) {
                                    System.out.println("Delete file: " + file.getAbsolutePath());
                                    file.delete(); // 删除文件
                                }
                            }
                        }
                    } else if (result == 143) {
                        System.out.println("手动终止训练。");
                        trainMission.setStatus("训练异常"); // 训练失败
                    } else {
                        System.out.println("result: " + result);
                        System.out.println("训练失败");
                        trainMission.setStatus("训练异常"); // 训练失败
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    trainMission.setStatus("未训练"); // 设置状态为未开始
                } finally {
                    processMap.remove(id);
                    trainMission.setRunning(false); // 设置为停止
                    trainMissionMapper.updateTrainMission(trainMission);


                    // 如果全局停止标志未设置，继续检查是否有下一个任务
                    if (!stopFlag) {
                        // 启动下一个任务
//                        doTrain();
                    } else {
//                        System.out.println("全局停止标志已设置，停止后续任务启动");
                    }
                }
            });
        } else {
            System.out.println("process有问题");
            trainMission.setStatus("未训练"); // 设置状态为未开始
            trainMission.setRunning(false); // 设置为停止
            trainMissionMapper.updateTrainMission(trainMission);
            return 1; // 启动 Python 进程失败，返回1
        }

        return 0;
    }

    @Override
    // 停止单独训练
    public boolean stopSingleTraining(int id) {
        lock.lock(); // 加锁，确保在停止期间没有其他任务操作
        try {
            // 检查全局停止标志，如果已设定，返回 false 表示无法单独停止
            if (stopFlag) {
                System.out.println("全局停止标志已设置，无法单独停止任务");
                return false;
            }

            System.out.println("processMap: " + processMap.toString());
            Process process = processMap.get(id);

            if (process != null) {
                // 终止进程
                process.destroy();
                try {
                    stopFlag = true; // 设置停止标志
                    process.waitFor(); // 等待进程完全结束
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                processMap.remove(id); // 从 processMap 中移除该进程

                // 更新任务状态
                TrainMission trainMission = trainMissionMapper.selectTrainMissionById(id);
                if (trainMission != null) {
                    trainMission.setStatus("未训练"); // 将任务状态设置为未开始
                    trainMission.setRunning(false); // 设置为停止
                    trainMissionMapper.updateTrainMission(trainMission);
                }

                return true; // 返回 true 表示成功停止任务
            }
            System.out.println("任务未找到或已停止");
            return false; // 如果进程不存在，返回 false
        } finally {
            stopFlag = false; // 操作完成后，允许以后再次启动任务
            lock.unlock(); // 释放锁
        }
    }

    @Override
    public int updateStatusToWait(int id) {
        TrainMission trainMission = trainMissionMapper.selectTrainMissionById(id);
        if (trainMission != null) {
            trainMission.setStatus("待训练"); // 将任务状态设置为待训练
            trainMission.setRunning(false); // 设置为停止
            trainMissionMapper.updateTrainMission(trainMission);
            return 1;
        } else {
            return 0;
        }
    }

    @Override
    public int updateStatusToNotTrain(int id) {
        TrainMission trainMission = trainMissionMapper.selectTrainMissionById(id);
        if (trainMission != null) {
            trainMission.setStatus("未训练"); // 将任务状态设置为未开始
            trainMission.setRunning(false); // 设置为停止
            trainMissionMapper.updateTrainMission(trainMission);
            trainMissionMapper.setTimeToQueueNull(id);
            return 1;
        } else {
            return 0;
        }
    }

    @Override
    public List<TrainMission> selectWaitAndTrainingList() {
        return trainMissionMapper.selectWaitAndTrainingList();
    }

    @Override
    public int stopTraining() {
        lock.lock(); // 加锁，确保在停止期间没有其他任务启动
        try {
            stopFlag = true; // 设置停止标志
            boolean allTerminated = true;

            // 遍历 processMap 中的所有进程，终止每个进程
            for (Map.Entry<Integer, Process> entry : processMap.entrySet()) {
                Process process = entry.getValue();
                int trainMissionId = entry.getKey();

                if (process.isAlive()) {
                    process.destroy(); // 终止进程
                    try {
                        process.waitFor(); // 等待进程完全结束
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        allTerminated = false; // 如果等待进程时发生异常，标记为未完全终止
                    }

                    // 更新训练任务状态为停止
                    TrainMission trainMission = trainMissionMapper.selectTrainMissionById(trainMissionId);
                    if (trainMission != null) {
                        trainMission.setStatus("未训练"); // 将任务状态设置为未开始
                        trainMission.setRunning(false); // 设置为停止
                        trainMissionMapper.updateTrainMission(trainMission);
                    }
                }
            }

            // 清空 processMap
            processMap.clear();

            return allTerminated ? 0 : 1; // 返回 0 表示成功终止所有进程，1 表示部分进程未成功终止
        } finally {
            stopFlag = false; // 操作完成后，允许以后再次启动任务
            lock.unlock(); // 释放锁
        }
    }

    // 启动训练任务
    @Override
    public int doTrain() {
        lock.lock(); // 加锁，确保任务执行的互斥性
        try {
            if (stopFlag) {
                // 如果正在停止任务，直接返回
                return 1;
            }

            int result = 0; // Python 脚本的运行结果，0 为正常退出
            int status = trainMissionMapper.isTraining(); // 检查当前的训练状态
//            System.out.println("status：" + status);

            if (processMap.isEmpty()) {
                //把所有训练中任务设置为待训练
                List<TrainMission> trainMissions = trainMissionMapper.queryStatusTrainingList();
                for (TrainMission trainMission : trainMissions) {
                    trainMission.setStatus("待训练");
                    trainMission.setRunning(false);
                    trainMissionMapper.updateTrainMission(trainMission);
                }
            }


            //且map为空
            if (status == 0 && processMap.isEmpty()) {
                List<TrainMission> pendingMissions = trainMissionMapper.queryStatusWaitList(null); // 查询状态为 “待训练” 的任务列表
                if (!pendingMissions.isEmpty()) {
                    TrainMission trainMission = pendingMissions.get(0); // 选取第一个未开始的任务

                    /*
                    调用startSingleTrain方法
                     */
                    result = startSingleTraining(trainMission.getId());

//                    int batchSize = trainMission.getBatchSize();
//                    int epoch = trainMission.getMaxEpoch();
//                    int earlyStop = trainMission.getEarlyStop();
//                    double lr = trainMission.getOpLr();
//
//                    // 更新任务状态为“训练中”
//                    trainMission.setStatus("训练中");
//                    trainMission.setRunning(true); // 设置为运行中
//                    trainMission.setBeginTime(new java.util.Date());
//                    trainMissionMapper.updateTrainMission(trainMission);
//
//                    //获取当前路径
//                    String currentPath = System.getProperty("user.dir");
//                    String parentParentPath = Utils.getParentPath(currentPath, 0);
//                    currentPath = parentParentPath + "/src/main/resources/CorsicanFire/segmentation";
//                    System.out.println("currentPath: " + currentPath);
//
//                    System.out.println(trainMission.getId());
//                    System.out.println(trainMission.getModel());
//                    System.out.println(modelServiceImpl.selectModelById(trainMission.getModelId()).getUserId());
//                    System.out.println(app01DatasetService.selectApp01DatasetById(trainMission.getDatasetTrainId()).getLocation());
//                    System.out.println(app01DatasetService.selectApp01DatasetById(trainMission.getDatasetTrainId()).getName());
//                    System.out.println(app01DatasetService.selectApp01DatasetById(trainMission.getDatasetValId()).getLocation());
//                    System.out.println(app01DatasetService.selectApp01DatasetById(trainMission.getDatasetValId()).getName());
//                    System.out.println(batchSize);
//                    System.out.println(trainMission.getMinEpoch());
//                    System.out.println(epoch);
//                    System.out.println(earlyStop);
//                    System.out.println(lr);
//                    System.out.println(trainMission.getModelId());

//                    if (trainMission.getIsWeight() && modelServiceImpl.selectModelById(trainMission.getModelId()).getIsWeight()) {
//                        // 构建源文件路径
//                        System.out.println("加载预训练模型");
//                        String pretrainModelLocation = modelServiceImpl.selectModelById(trainMission.getModelId()).getLocation();
//                        int lastSlashIndex = pretrainModelLocation.lastIndexOf("/");
//                        if (lastSlashIndex != -1) {
//                            pretrainModelLocation = pretrainModelLocation.substring(0, lastSlashIndex);
//                        }
//
//                        // 拼接最终的源文件路径
//                        String sourceFilePath = pretrainModelLocation + "/1.pth";
//
//                        // 构建目标文件路径
//                        String pretrainModelPath = parentParentPath + "/src/main/resources/trainResult" + "/" + trainMission.getId() + "/predictResult/1.pth";
//
//                        // 调用文件复制方法
//                        try {
//                            Utils.copyFile(sourceFilePath, pretrainModelPath);
//                        } catch (IOException e) {
//                            throw new RuntimeException(e);
//                        }
//                    }
//
//                    // 训练异常记录txt文件存储位置
//                    String exceptionRecordPath = parentParentPath + "/src/main/resources/trainResult" + "/" + trainMission.getId() + "/exceptionRecord.txt";
//
//                    // 启动 Python 脚本并获取进程对象
//                    Process process = RunPythonScript.runCommandWithParaProcess(
//                            currentPath + "/RunCommand.py",
//                            trainMission.getId(),
//                            trainMission.getModel(),
//                            modelServiceImpl.selectModelById(trainMission.getModelId()).getUserId(),
//                            app01DatasetService.selectApp01DatasetById(trainMission.getDatasetTrainId()).getLocation(),
//                            app01DatasetService.selectApp01DatasetById(trainMission.getDatasetTrainId()).getName(),
//                            app01DatasetService.selectApp01DatasetById(trainMission.getDatasetValId()).getLocation(),
//                            app01DatasetService.selectApp01DatasetById(trainMission.getDatasetValId()).getName(),
//                            batchSize,
//                            trainMission.getMinEpoch(),
//                            epoch,
//                            earlyStop,
//                            lr,
//                            trainMission.getModelId(),
//                            exceptionRecordPath
//                    );
//
//
//                    if (process != null) {
//                        // 将进程添加到 processMap 中
//                        processMap.put(trainMission.getId(), process);
//
//                        executorService.submit(() -> {
//                            try {
//                                int exitCode = process.waitFor(); // 等待进程完成并获取结果
//                                if (exitCode == 0) {
//                                    trainMission.setStatus("已完成"); // 任务成功完成
//                                    trainMission.setendTime(new java.util.Date());
//                                } else {
//                                    trainMission.setStatus("训练异常"); // 任务失败，恢复为未开始状态
//
//                                }
//                            } catch (InterruptedException e) {
//                                e.printStackTrace();
//                                trainMission.setStatus("未训练"); // 中断异常时设为未开始
//                            } finally {
//                                processMap.remove(trainMission.getId()); // 移除已完成的进程
//
//                                trainMissionMapper.updateTrainMission(trainMission);
//                                if (!stopFlag) { // 检查是否还有待执行的任务，并确保没有停止标志
//                                    doTrain(); // 递归调用，启动下一个任务
//                                }
//                            }
//                        });
//                    } else {
//                        // 启动 Python 进程失败，恢复任务状态为未开始
//                        trainMission.setStatus("训练异常");
//                        trainMissionMapper.updateTrainMission(trainMission);
//                        result = 1; // 返回 1 表示进程启动失败
//                    }
                }
            } else {
                System.out.println("已有任务在训练中，等待任务完成。");
            }

            return result; // 返回结果
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    @Override
    public List<TrainMission> selectFinishedList(TrainMission trainMission) {
        return trainMissionMapper.selectFinishedList(trainMission);
    }

    @Override
    public int deleteTrainMissionById(Integer id) {
        TrainMission trainMission = trainMissionMapper.selectTrainMissionById(id);
//		获取当前路径
        String currentPath = System.getProperty("user.dir");
//		构造删除文件路径，为/predictResult/trainMissionId/datasetId/下的文件
        String deletePath = currentPath + "/src/main/resources/trainResult/" + (trainMission.getId()) + "/";
        System.out.println("deletePath: " + deletePath);
        //删除文件
        FileUtils.deleteFolderFile(deletePath);
        //删除数据库记录
//		成功返回1，失败返回0
//		int i = predictMapper.deletePredictById(id);
//		System.out.println("i"+i);
        return 1;
    }

    @Override
    public void setTimeToQueue(int id) {
        trainMissionMapper.setTimeToQueue(id);
    }

    @Override
    public boolean isTrainMissionNameExists(String trainMissionName, int userId) {
        Integer count = trainMissionMapper.isTrainMissionNameExists(trainMissionName, userId);
        return count != null && count > 0;
    }

    @Override
    public int calculateQueuePosition(Date timeToQueue, int id) {
        // 查询所有任务并根据 timeToQueue 排序，找到当前任务的队列位次
        List<TrainMission> missions = trainMissionMapper.selectAllTrainMissionsOrderedByTime();
        int position = 1;

        for (TrainMission mission : missions) {
            if (mission.getId() == id) {
                break;
            }
            position++;
        }

        return position;
    }

    @Override
    public List<TrainMission> selectTrainMissionListByUser(int currentUserId, TrainMission trainMission) {
        List<TrainMission> trainMissions = trainMissionMapper.selectTrainMissionListByUser(currentUserId, trainMission);
        return trainMissions;
    }

    @Override
    public List<TrainMission> selectTrainMissionListWithUserOrPublic(Integer currentUserId, TrainMission trainMission) {
        List<TrainMission> trainMissions = trainMissionMapper.selectTrainMissionListWithUserOrPublic(currentUserId, trainMission);
        return trainMissions;
    }


}
